package com.sun.dream.fish.secret.mac;

import org.bouncycastle.crypto.engines.ChaChaEngine;
import org.bouncycastle.crypto.macs.Poly1305;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

public class Poly1305Example {
    public static void main(String[] args) {
        String message = "Hello World";
        byte[] key = generateRandomKey(); // Generate a 256-bit random key

        byte[] mac = calculatePoly1305MAC(message.getBytes(StandardCharsets.UTF_8), key);

        System.out.println("Poly1305 MAC of \"" + message + "\": " + bytesToHex(mac));
    }

    public static byte[] calculatePoly1305MAC(byte[] message, byte[] key) {
        ChaChaEngine chacha20 = new ChaChaEngine();
        chacha20.init(true, new ParametersWithIV(new KeyParameter(key), new byte[8]));

        byte[] macKey = new byte[32];
        chacha20.processBytes(macKey, 0, macKey.length, macKey, 0);

        Poly1305 mac = new Poly1305();
        mac.init(new KeyParameter(macKey));

        mac.update(message, 0, message.length);
        byte[] macResult = new byte[mac.getMacSize()];
        mac.doFinal(macResult, 0);

        return macResult;
    }

    public static byte[] generateRandomKey() {
        byte[] key = new byte[32];
        SecureRandom random = new SecureRandom();
        random.nextBytes(key);
        return key;
    }

    public static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString();
    }
}